Skip to content

feat(jvm): Add multi-certificate and system truststore support for CAcerts#6441

Merged
squakez merged 5 commits intoapache:mainfrom
pkalsi97:feat/6432
Jan 20, 2026
Merged

feat(jvm): Add multi-certificate and system truststore support for CAcerts#6441
squakez merged 5 commits intoapache:mainfrom
pkalsi97:feat/6432

Conversation

@pkalsi97
Copy link
Contributor

@pkalsi97 pkalsi97 commented Jan 13, 2026

This PR improves the JVM trait's CA certificate handling to address the issues reported in #6432.

Features

  • Structured Certificate Configuration: New ca-certificates field accepts a list of CACertConfig{certPath} entries for importing multiple PEM certificates
  • Explicit Truststore Password: New truststore-password-path field for specifying the output truststore password (PEM certificates don't have passwords, only the truststore does)
  • Base Truststore Support: New base-truststore field allows using an existing truststore (e.g., JDK cacerts) as the starting point for adding custom certificates
  • Password Priority: truststore-password-pathbase-truststore.password-path → legacy ca-cert-password
  • Deprecated Legacy Fields: ca-cert and ca-cert-password are deprecated in favor of the new structured fields
  • Added 4 E2E tests covering single cert, multiple certs, base truststore, and backward compatibility

Fix

  • Passwords are now read from files at runtime using -storepass:file (keytool), never hardcoded
  • Removed default changeit password - users must explicitly provide password files for security

Examples

Single Certificate

kamel run MyRoute.java \
  -t mount.configs=secret:my-ca \
  -t mount.configs=secret:truststore-pass \
  -t jvm.ca-certificates[0].cert-path=/etc/camel/conf.d/_secrets/my-ca/ca.crt \
  -t jvm.truststore-password-path=/etc/camel/conf.d/_secrets/truststore-pass/password

Multiple Certificates

  kamel run MyRoute.java \
    -t mount.configs=secret:ca1 \
    -t mount.configs=secret:ca2 \
    -t mount.configs=secret:truststore-pass \
    -t jvm.ca-certificates[0].cert-path=/etc/camel/conf.d/_secrets/ca1/ca.crt \
    -t jvm.ca-certificates[1].cert-path=/etc/camel/conf.d/_secrets/ca2/ca.crt \
    -t jvm.truststore-password-path=/etc/camel/conf.d/_secrets/truststore-pass/password

With Base Truststore (preserve JDK public CAs)

  kamel run MyRoute.java \
    -t mount.configs=secret:my-ca \
    -t mount.configs=secret:cacerts-pass \
    -t jvm.base-truststore.truststore-path=/opt/java/openjdk/lib/security/cacerts \
    -t jvm.base-truststore.password-path=/etc/camel/conf.d/_secrets/cacerts-pass/password \
    -t jvm.ca-certificates[0].cert-path=/etc/camel/conf.d/_secrets/my-ca/ca.crt

Note: When using base-truststore, you can optionally provide truststore-password-path to set a different password for the output truststore. If not provided, the base truststore password is used.

Deprecated Syntax (backward compatible)

  kamel run MyRoute.java \
    -t mount.configs=secret:my-ca \
    -t mount.configs=secret:my-password \
    -t jvm.ca-cert=/etc/camel/conf.d/_secrets/my-ca/ca.crt \
    -t jvm.ca-cert-password=/etc/camel/conf.d/_secrets/my-password/password

@github-actions
Copy link
Contributor

✔️ Unit test coverage report - coverage increased from 60.8% to 61.2% (+0.4%)

Copy link
Contributor

@squakez squakez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great works, thanks for taking care. However, we need to make a few changes to make it more consistent and secure.

  1. The passwords must be specified by final user. What we need to do is to provide some mechanism to make sure we correctly associate the parameter file with the parameter passwords (for example, implementing an internal simple struct to have file/passwordFile and referring it in the object like done in Keda trait).
  2. Make the user provide the path to the existing trusstore to merge. There is no easy way to make it sure we identify the valid truststore the final user wants to use (it also depends on the base image chosen). We can add a parameter for that and just use it straight for merge.
  3. If we're going for a list of cacerts, then, we need to deprecate the existing single cacert file/password parameter.

@pkalsi97
Copy link
Contributor Author

@squakez thanks for the review and the feedback. i'll keep this in mind.
I have incorporated your suggestions also i have updated the PR description.

Need input on user provided paths (like certPath, passwordPath, truststorePath) are used directly in shell commands for the init container, shall i add a path validation.

I was not able to run the E2E test locally, not sure but my local setup due to Maven dependency download issues during integration builds.

@pkalsi97 pkalsi97 requested a review from squakez January 15, 2026 06:38
@github-actions
Copy link
Contributor

✔️ Unit test coverage report - coverage increased from 60% to 61.2% (+1.2%)

@github-actions
Copy link
Contributor

✔️ Unit test coverage report - coverage increased from 59.9% to 61.2% (+1.3%)

Copy link
Contributor

@squakez squakez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have it. Only some doubts around the usage of the base trustore password.

@pkalsi97
Copy link
Contributor Author

@squakez Thanks! i resonate with you, preserving the base truststore password will result in a much more simplified implementation i have made changes to reflect the same.

@github-actions
Copy link
Contributor

✔️ Unit test coverage report - coverage increased from 60% to 61.2% (+1.2%)

@pkalsi97
Copy link
Contributor Author

I have implemented a simplified approach incorporating your suggestion. This will make the whole process more simpler (I hope so) and explicit.

Added explicit truststore-password-path, Users provide the password for the generated truststore.
Password priority follows your suggestion:
truststore-password-path → base-truststore.password-path → ca-cert-password → validation error

Base truststore handling: When both base-truststore and truststore-password-path are set, we:

  • Copy the base truststore
  • Import certs using the base truststore's password
  • Change the password to the user-specified one at the end

Removed per-certificate passwordPath from CACertConfig, only the truststore needs password.

Copy link
Contributor

@squakez squakez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, thanks!

@github-actions
Copy link
Contributor

✔️ Unit test coverage report - coverage increased from 60.1% to 61.2% (+1.1%)

@pkalsi97
Copy link
Contributor Author

@squakez thanks a lot for your thoughtful guidance and review! It really helped me think better in terms of user experience.

@squakez squakez merged commit c2ef248 into apache:main Jan 20, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants